<?php
require_once('lanceur_spip.php');
include_spip('functions/pdk_common');

require_once(_DIR_PLUGIN_PDK.'classes/simpletest/class.PdkModelTest.php');

/**
 *  AlohacartOrderModel class test case
 */
class TestClassAlohacartOrderModel extends PdkModelTest {        
    /**
     *  Alohacart
     */
    private $cart;
    
    /**
     * AlohacartOrderProductModel
     */
    private $order_product_mdl;
    
    /**
     * AlohacartOrderStatutModel
     */
    private $order_statut_mdl; 
    
    /**
     *  EcataloguE ProductModel
     */
    private $product_mdl;
    
    /**
     *  PdkArticleModel 
     */
    private $article_mdl;
    
    /**
     *  PdkRubriqueModel 
     */
    private $rubrique_mdl;
    
    /**
     *  AlohacartExtensionModel
     */
    private $extension_mdl;
    
    /**
     *  AlohacartExtensionModel
     */
    private $currency_mdl;
    
    /**
     *  RubriqueCurrencyModel
     */
    private $rub_currency_mdl;
    
    /**
     *  CompositeArticleModel
     */
    private $composite_art_mdl;
    
    /**
     *  AlohacartShippingFlat
     */
    //private $shipping_flat;
    
    /**
     *  AlehacartPaymentBankTransfer
     */
    //private $payment_bank;
    
    /**
     *  Price precision
     */
    private $price_precision;
    
    function __construct(){
        parent::__construct();
        
        $pdk_models = array();
        
        $this->order_product_mdl = pdk_load_class('AlohacartOrderProductModel','classes');
        $pdk_models['AlohacartOrderProductModel'] = $this->order_product_mdl;
        $this->product_mdl = pdk_load_class('ProductModel','classes');
        $pdk_models['ProductModel'] = $this->product_mdl;        
        $this->product_mdl = pdk_load_class('ProductModel','classes');
        $pdk_models['ProductModel'] = $this->product_mdl;
        $this->article_mdl = pdk_load_class('PdkArticleModel','classes');
        $pdk_models['PdkArticleModel'] = $this->article_mdl;
        $this->rubrique_mdl = pdk_load_class('PdkRubriqueModel','classes');
        $pdk_models['PdkRubriqueModel'] = $this->rubrique_mdl;
        $this->extension_mdl = pdk_load_class('AlohacartExtensionModel','classes');
        $pdk_models['AlohacartExtensionModel'] = $this->extension_mdl;
        $this->currency_mdl = pdk_load_class('CurrencyModel', 'classes');
        $pdk_models['CurrencyModel'] = $this->currency_mdl;
        $this->rub_currency_mdl = pdk_load_class('RubriqueCurrencyModel', 'classes');
        $pdk_models['RubriqueCurrencyModel'] = $this->rub_currency_mdl;
        $this->composite_art_mdl = pdk_load_class('CompositeArticleModel', 'classes');
        $pdk_models['CompositeArticleModel'] = $this->composite_art_mdl;
        $this->order_statut_mdl = pdk_load_class('AlohacartOrderStatutModel', 'classes');
        $pdk_models['AlohacartOrderStatutModel'] = $this->order_statut_mdl;
        
        $this->AddPdkModels($pdk_models);
                
        $this->SetPdkModel('AlohacartOrderModel', pdk_load_class('AlohacartOrderModel', 'classes'));
        
        //$this->shipping_flat = pdk_load_class('AlohacartShippingFlat','classes/shipping');
        //$this->payment_bank = pdk_load_class('AlohacartPaymentBankTransfer','classes/payment');
        
        $this->cart = pdk_load_class('Alohacart','classes');
        
        $this->price_precision = lire_config('ecatalogue/price_pricision'); if (!$this->price_precision) $this->price_precision = 2;
                        
        $this->dropTestTables = TESTS_DROP_TEST_TABLES;
        
        // Remember what is written in cart
        @session_start();
        $this->session_cart_variable = $_SESSION["alohacart"];
        
        // Remember what is written in config
        $this->shipping_config = lire_config('alohacart/shipping_flat');
        // Remember current currency
        $this->session_current_currency_id = $_SESSION["current_currency_id"];        
    }
        
    /**
     *  Run before each test
     */
    function setUp() {
        parent::setUp();
    }
    
    /**
     *  Run after each test
     */
    function tearDown() {
        parent::tearDown();
    }
    
    function __destruct() {
        parent::__destruct();
        
        // Return cart in initial state
        $_SESSION["alohacart"] = $this->session_cart_variable;
        // Rewrite config with initial data
        ecrire_config('alohacart/shipping_flat', $this->shipping_config);
        // Return current currency ID into initital state
        //$this->currency_mdl->SetCurrentCurrencyId($this->current_currency_id);
        $_SESSION["current_currency_id"] = $this->session_current_currency_id;
        //$this->cart->ClearCart();        
    }
    
    function Test_CreateOrder() {
        // Let's make product #2 composite and it's price 0. So when calculated, price will be summ of #3 and #4 products
        $this->product_mdl->update_by_id(2, array('price'=>0, 'is_composite'=>1));
        
        // Set current currency ID. Although it's rate != 1, order prices must be saved in conventional currency (rate=1)
        $this->currency_mdl->SetCurrentCurrencyId(1);
        $this->currency_mdl->main_currency_id = 2;
        
        // Let's change shipping's config a little bit - set id_currency to 1 (this currency exists)
        $config = $this->shipping_config;
        $config['id_currency'] = 1;
        ecrire_config('alohacart/shipping_flat', $config); 
        
        // Let's clear Cart, Odrers and OrdersProducts tables for this test
        $this->cart->ClearCart();
        $this->model->delete();
        $this->order_product_mdl->delete();
        
        $this->cart->AddProduct(1, 1);        
        $this->cart->AddProduct(2, 2);
        $this->cart->AddProduct(3, 3);
        
        $order_data = $this->model->test_data[0];
        unset($order_data['date']); // Current date must be substituted automatically
        unset($order_data['id_statut']); // NewOrderStatut must be substituted automatically
        unset($order_data['shipping_cost']); // Shipping cost must be calculated automatically
        unset($order_data['shipping_titre']); // Shipping titre must be got from extension        
        unset($order_data['shipping_data']); // Shipping data must be got from extension
        unset($order_data['payment_titre']); // Payment titre must be got from extension
        unset($order_data['payment_data']); // Payment data must be got from extension
        unset($order_data['total_price']); // Total price must be calculated automatically
        unset($order_data['id_currency']); // id currency will be taken as current currency
        unset($order_data['currency_rate']); // currency rate will be taken from current currency
         
        $id_order = $this->model->CreateOrder($order_data);
        
        // Created order ID must be > 0
        $this->assertTrue(intval($id_order)>0);
        
        // 1 order and 3 order-product links must be created
        $this->assertEqual(1, $this->model->get_total());
        $this->assertEqual(3, $this->order_product_mdl->get_total());
        
        // Check order data
        $order = $this->model->select();
        $order = $order[0];        
        $order_data['id_statut'] = $this->model->NewOrderStatut;
        //$order_data['shipping_cost'] = $this->model->test_data[0]['shipping_cost'];
        //$order_data['shipping_cost'] = $this->shipping_flat->GetCost(); // Shipping cost is calculated in extension
        $order_data['shipping_titre'] = $this->extension_mdl->test_data[0]['titre']; //Take from extension
        $shipping_class = $this->extension_mdl->GetExtensionClassByID($order_data['id_shipping']);        
        $order_data['shipping_cost'] = $shipping_class->GetCost(); // Shipping cost must be calculated via extension class
        $order_data['shipping_data'] = $shipping_class->GetData();// Shipping data must be got via extension class
        
        $order_data['payment_titre'] = $this->extension_mdl->test_data[2]['titre']; //Take from extension
        $payment_class = $this->extension_mdl->GetExtensionClassByID($order_data['id_payment']);        
        $order_data['payment_data'] = $payment_class->GetData(); // Payment data must be got via extension class
        
        // How order's total price must be calculated (in main currency)
        $total_price = $this->product_mdl->test_data[0]['price']*1+ // Price of product #1
                       $this->product_mdl->test_data[2]['price']*$this->composite_art_mdl->test_data[2]['quantity']*2+ // Price of product #3 as part of composite product #2
                       $this->product_mdl->test_data[3]['price']*$this->composite_art_mdl->test_data[3]['quantity']*2+ // Price of product #4 as part of composite product #2
                       $this->product_mdl->test_data[2]['price']*3+ // Price of product #3
                       //$this->product_mdl->GetProductPrice(1) + $this->product_mdl->GetProductPrice(2) + $this->product_mdl->GetProductPrice(3) + 
                       $order_data['shipping_cost'];
        // We'll check with price precision = 2
        $order_data['total_price'] = round($total_price, 2); 
        $order['total_price'] = round($order['total_price'], 2);
         
        $current_currency = $this->currency_mdl->GetCurrentCurrency();
        $order_data['id_currency'] = $current_currency['id_currency']; 
        $order_data['currency_rate'] = $current_currency['rate'];
        
        //$order_data['statut_titre'] = $current_currency['rate'];
        
        $order_data['date'] = $order['date']; // Do date fields equal to avoid long tests problems
        $this->assertEqual($order_data, $order);
        
        // Check order products data
        $order_products = $this->order_product_mdl->select(false, false, 'id_article');                
        foreach ($order_products as $key=>$order_product) {
            $order_product_data = $this->order_product_mdl->test_data[$key];
            // Because product #2 is composite with price=0, it's price must be summ of #3 and #4 products            
            if ($order_product_data['id_order_product']==2) {
                $order_product_data['price'] = $this->order_product_mdl->test_data[2]['price']*$this->composite_art_mdl->test_data[2]['quantity'] + 
                                               $this->order_product_mdl->test_data[3]['price']*$this->composite_art_mdl->test_data[3]['quantity'];
                $order_product_data['total_price'] = $order_product_data['price']*$order_product_data['quantity']; 
                
            }
            $order_product_data['id_order'] = $id_order;
            $order_product_data['id_order_product'] = $order_product['id_order_product']; // id_order_product is auto increment
            $order_product_data['written_off'] = $order_product['written_off'];
            $this->assertEqual($order_product_data, $order_product);
        }
    }
    
    function Test_RecalculateOrder() {
        // We will do this test on order with ID = 1 
        // Let's change order's shipping total price, so later we can check if it is calculated properly
        $this->model->update_by_id(1, array('shipping_cost'=>300,'total_price'=>12345));
        
        // Let's delete all order product and insert few, so we can be sure in total price of order
        $this->order_product_mdl->delete();
        $this->order_product_mdl->insert(array('id_order'=>1,'total_price'=>100)); 
        $this->order_product_mdl->insert(array('id_order'=>1,'total_price'=>200));
        
        // Recalculate order
        $this->model->RecalculateOrder(1);
        
        // This is how order's total price must be calculated
        $total_price = 300 + 100 + 200;
        
        // Check wether order's total price was calculated properly:
        $order = $this->model->select_by_id(1);
        $this->assertEqual($total_price,$order['total_price']);
    }
    
    function Test_delete() {        
        $this->order_product_mdl->insert(array('id_order'=>1));
        $this->model->delete_by_id(1);
        // When order deleted, all it's products must be deleted too:
        $this->assertEqual(0,$this->order_product_mdl->get_total('id_order=1'));
        
        $this->order_product_mdl->insert(array('id_order'=>2));
        $this->model->delete('id_order=2');
        $this->assertEqual(0,$this->order_product_mdl->get_total('id_order=2'));
    }
    
    function Test_statuses_change() {
        // Add one more product to order #1
        $this->order_product_mdl->update_by_id(2, array('id_order'=>1));
        
        // Configure statuses by hand to perform the tests
        $this->model->write_off_statuts = array(2,4);
        $this->model->return_statuts = array(6);
        
        // Write off product #1
        $this->model->update_by_id(1, array('id_statut'=>2));
        $order_product = $this->order_product_mdl->select_by_id(1);
        $this->assertEqual(1, $order_product['written_off']);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(99, $product['quantity']);
        // Write off product #2
        $this->model->update_by_id(2, array('id_statut'=>4));
        $order_product = $this->order_product_mdl->select_by_id(2);
        $this->assertEqual(1, $order_product['written_off']);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(48, $product['quantity']);
        
        // Return product #1
        $this->model->update_by_id(1, array('id_statut'=>6));
        $order_product = $this->order_product_mdl->select_by_id(1);
        $this->assertEqual(0, $order_product['written_off']);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(100, $product['quantity']);
        // Return product #2
        $this->model->update_by_id(2, array('id_statut'=>6));
        $order_product = $this->order_product_mdl->select_by_id(2);
        $this->assertEqual(0, $order_product['written_off']);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(50, $product['quantity']);
    }
    
    function Test_statuses_change_Zero_quantity_left_after_write_off() {
        // Configure statuses by hand to perform the tests
        $this->model->write_off_statuts = array(2,4);
        $this->order_product_mdl->update_by_id(1, array('quantity'=>100));
        
        // Write off product #1
        $this->model->update_by_id(1, array('id_statut'=>2));
        $order_product = $this->order_product_mdl->select_by_id(1);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(0, $product['quantity']);
    }
    
    function Test_statuses_change_Negative_quantity_left_after_write_off() {
        // Configure statuses by hand to perform the tests
        $this->model->write_off_statuts = array(2,4);
        $this->order_product_mdl->update_by_id(1, array('quantity'=>150));
        
        // Write off product #1
        $this->model->update_by_id(1, array('id_statut'=>2));
        $order_product = $this->order_product_mdl->select_by_id(1);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(-50, $product['quantity']);
    }
    
    function Test_statuses_change_when_creating_order() {
        // Add one more status to write off statuses
        $this->model->write_off_statuts = array(1,2,4);
        
        // Write off product #1 when order added
        $this->cart->ClearCart();
        $this->cart->AddProduct(1, 1);
        $this->order_product_mdl->delete();
        $this->model->NewOrderStatut = 1;
        $id_order = $this->model->CreateOrder(array());
        $order_product = $this->order_product_mdl->select('id_order='.$id_order);
        $order_product = $order_product[0];
        $this->assertEqual(1, $order_product['written_off']);
        $product = $this->product_mdl->select_by_id($order_product['id_article']);
        $this->assertEqual(99, $product['quantity']);
    }
}